

package com.bonc.excel.controller.upload;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelAnalysisException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.util.*;

/**
 * @Description
 * @Author wujing
 */

@Slf4j
public abstract class AbstractAnalysisEventListener<T> extends AnalysisEventListener<T> {
    private static int BATCH_COUNT = 500;
    private List<T> dataList = null;
    private T data;
    private boolean NEED_BATCH_HANDLE = true;
    private boolean NEED_CHECK_TITLE = false;

    public AbstractAnalysisEventListener(Class<T> targetClz, int batchCount,boolean needBatchHandle,boolean needCheckHead) throws Exception {
        if(batchCount > 0){
            this.BATCH_COUNT = batchCount;
        }
        dataList = new ArrayList<>(BATCH_COUNT);
        NEED_BATCH_HANDLE = needBatchHandle;
        NEED_CHECK_TITLE = needCheckHead;
        data = targetClz.newInstance();

    }

    public AbstractAnalysisEventListener(){ dataList = new ArrayList<>(BATCH_COUNT);}


    /**
     *     读取Execl时，每读取一行行数据，会调用一次此方法
     * @param excelData
     * @param analysisContext
     */
    @Override
    public void invoke(T excelData, AnalysisContext analysisContext) {
        dataList.add(excelData);

        if (dataList.size() >= BATCH_COUNT && NEED_BATCH_HANDLE){
            handleBiz(dataList);
            dataList.clear();
        }
    }


    //所有数据解析完成了 都会来调用 ：防止最后不足BATCH_COUNT条的数据被遗漏
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        handleBiz(dataList);
        dataList.clear();
    }

    /**
     * @description:  校验excel头部格式，必须完全匹配
     * @param headMap 传入excel的头部（第一行数据）数据的index,name
     * @param context
     * @throws
     */
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        super.invokeHeadMap(headMap, context);
        if(data==null || !NEED_CHECK_TITLE){
            return;
        }
        //通过判断类注解是否需要校验title
      /* Class<?> aClass = data.getClass();
        aClass.isAnnotation()*/
        try {
            Map<Integer, String> indexNameMap = getIndexTitleNameMap(data.getClass());
            Set<Integer> keySet = indexNameMap.keySet();
            for (Integer key : keySet) {
                if (StringUtils.isEmpty(headMap.get(key))){
                    throw new ExcelAnalysisException("解析excel出错，请传入正确格式的excel");
                }
                String excelName = headMap.get(key);
                String modleName = indexNameMap.get(key);
                if (!excelName.equals(modleName)){
                    throw new ExcelAnalysisException("解析excel出错，请传入模板标题,第"+key+1+"列标题"+excelName+" 应该修改为:"+modleName);
                }
            }

        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }


    /**
     * @description: 获取注解里ExcelProperty的value，用作校验excel的标题
     * @param clazz
     * @throws
     */
    @SuppressWarnings("rawtypes")
    public Map<Integer,String> getIndexTitleNameMap(Class clazz) throws NoSuchFieldException {
        Map<Integer,String> result = new HashMap<>();
        Field field;
        Field[] fields=clazz.getDeclaredFields();
        for (int i = 0; i <fields.length ; i++) {
            field=clazz.getDeclaredField(fields[i].getName());
            field.setAccessible(true);
            ExcelProperty excelProperty=field.getAnnotation(ExcelProperty.class);
            if(excelProperty!=null){
                int index = excelProperty.index();
                if(-1 == index){
                    continue;
                }
                String[] values = excelProperty.value();
                StringBuilder value = new StringBuilder();
                for (String v : values) {
                    value.append(v);
                }
                result.put(index,value.toString());
            }
        }
        return result;
    }

    protected abstract void handleBiz(List<T> dataList);

}
